/**
 * Filters : 	alpha,
				alnum,
				numeric,
				lower,
				lcfirst,
				upper,
				ucfirst,
				ucwords,
				trim,
				ltrim,
				rtrim,
				nospace,
				sanitize,
				striptags
 *				
 * Types :		color
				email
				file
				ip
				uniqid
				url		
 */

var FormCheck = new Class({
	Implements: [Events, Options],
	
	options: {
		
	},
	
	langs : [],
	fields : [],
	
	initialize: function(obj, options){
		this.setOptions(options);
		this.constraints = obj;
		this.form = $$('form')[0];
		this.submit = $$('div.login_submit')[0];
		
		this.initTab();
		
		this.parseFieldInfos();
		this.formState();
	},
	
	/*
	 * Prepare the object of field infos
	 */
	initTab: function(){
		for (var lang in this.constraints){
			this.langs.push(lang);
			for (var field in this.constraints[lang]){
				this.fields.push(this.constraints[lang][field]);
			}
		}
	},
	
	/*
	 * Parse the object of field infos
	 */
	parseFieldInfos: function(){
		this.fields.each(function(field, index){
			if (field.type != 'radio'){
				var element = $(field.id);
				var event = 'blur';
				
				switch (element.tagName.toLowerCase()){
					case 'input':
						if (field.specific_type == 'fk'){
							element = $(element.get('id')+'_label');
							event = 'select';
							element.retrieve('AutoComplete').addEvent('select', function(){
								this.dispatcher.delay(100, this, [element, field]);
							}.bind(this));
						}
						else if (element.get('type') == 'file')
							event = 'change';
						else if (field.specific_type == 'address'){
							new google.maps.places.Autocomplete(element);
						}
						break;
					case 'textarea':
						if (typeOf(window.CKEDITOR) == 'object' && this.inArray(field.id, ckFields)){
							(function(){
								CKEDITOR.instances[element.get('id')].on('blur', function(){
									this.dispatcher(element, field);
								}.bind(this));
							}).delay(1000, this)
						}
						break;
				}
				
				element.store('constraints', field);
				
				if (event != 'select'){
					element.addEvent(event, function(){
						this.dispatcher.delay(100, this, [element, field]);
					}.bind(this));
				}
				
				(function(){
					this.buildTick(element);
					this.dispatcher(element, field);
				}).delay(200, this);
			}
		}.bind(this));
	},
	
	/*
	 * Applies required, filter, and specific type functions to the field value
	 */
	dispatcher: function(element, field){
		// Check if the value if empty 
		if (field.required == true)
			this.required(element);
		
		// Apply fitlers on value
		if (field.filters.length > 0)
			this.filter(element);
		
		// Format value to the right specific type
		if (field.specific_type != '')
			this.specificType(element);
		
		this.check(element);
		this.formState();
	},
	
	/*
	 * Checks if the field value is not empty
	 */
	required: function(element){
		if (element.retrieve('constraints').required == true){
			var tick = element.retrieve('tick');
			var error_message =  element.retrieve('error_message');
			
			if (!this.getValue(element) || this.getValue(element) == ''){
				tick.removeClass('success').addClass('error');
				error_message.set('html', element.retrieve('constraints').label+' '+slsBuild.langs.SLS_E_EMPTY);
				error_message.removeClass('hidden');
				return false;
			} else {
				tick.removeClass('error').addClass('success');
				error_message.addClass('hidden');
				return true;
			}
		}
	},
	
	/*
	 * Applies filter(s) to the field value
	 */ 
	filter: function(element){
		var field = element.retrieve('constraints');
		var value = this.getValue(element);
		
		field.filters.each(function(filter){
			switch (filter){
				case 'striptags':
					value = value.replace(/(<([^>]+)>)/ig,"");
					break;
					
				case 'lower':
					value = value.toLowerCase();
					break;
					
				case 'lcfirst':
					value = value.charAt(0).toLowerCase()+value.slice(1);
					break;
					
				case 'upper':
					value = value.toUpperCase();
					break;
					
				case 'ucfirst':
					value = value.charAt(0).toUpperCase()+value.slice(1);
					break;
					
				case 'alpha':
					value = value.replace(/[^A-Za-z]/g, '');
					break;
					
				case 'alnum':
					value = value.replace(/[^A-Za-z0-9]/g, '');
					break;
					
				case 'numeric':
					value = value.replace(/[^0-9]/g, '');
					break;
					
				case 'ucwords':					
				    value = (value + '').replace(/^([a-z])|\s+([a-z])/g, function ($1) {
				        return $1.toUpperCase();
				    });
					break;
					
				case 'trim':
					value = value.replace(/^\s+/,"");
					value = value.replace(/\s+$/,"");
					break;
					
				case 'ltrim':
					value = value.replace(/^\s+/,"");
					break;
					
				case 'rtrim':
					value = value.replace(/\s+$/,"");
					break;
					
				case 'nospace':
					value = value.replace(/ /g, '');
					break;
					
				case 'sanitize':
					
					break;
			}
		}.bind(this));
			
		this.setValue(element, value);
	},
	
	/*
	 * Checks if the field value meets the type associated
	 */
	specificType: function(element){
		var field = element.retrieve('constraints');
		var value = this.getValue(element);
		var error = false;
		
		switch (field.specific_type){
			case 'email':
				var regex = /^[-a-z0-9~!$%^&*_=+}{\'?]+(\.[-a-z0-9~!$%^&*_=+}{\'?]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$/i;
				if (!regex.test(value))
					error = true;
				break;
			case 'color':
				var regex = /^#?(([a-fA-F0-9]){3}){1,2}$/;
				if (!regex.test(value))
					error = true;
				break;
				
			case 'ip_both':
				if (!this.type_isIpV4(value) && !this.type_isIpV6(value))
					error = true;
				break;
				
			case 'ip_v4':
				if (!this.type_isIpV4(value))
					error = true;
				break;
				
			case 'ip_v6':
				if (!this.type_isIpV6(value))
					error = true;
				break;
				
			case 'uniqid':
				var regex = /^[a-z0-9]*$/;
					if (!regex.test(value))
						error = true;
				break;
				
			case 'url':
				var regex = /^(http:\/\/|https:\/\/)(([a-z0-9]([-a-z0-9]*[a-z0-9]+)?){1,63}\.)+[a-z]{2,6}/i;
				if (!regex.test(value))
					error = true;
				break;
			case 'fk':
				if (!this.required(element) && field.required == true)
					error = true;
				break;
			case 'file':
				var regex = /\.(jpg|jpeg|png|gif|xbm)$/i;
				if ((!this.required(element) && field.required == true) || (field.type == 'file_img' && !regex.test(value) && value != ''))
					error = true;
				break;
		}
		
		if (error && (field.required || (!field.required && value != ''))){
			element.retrieve('tick').removeClass('success').addClass('error');
			
			if (element.retrieve('error_message').hasClass('hidden')){
				element.retrieve('error_message').set('html', element.retrieve('constraints').label+' '+slsBuild.langs.SLS_E_TYPE);
				element.retrieve('error_message').removeClass('hidden');
			}
		}
		else if (!element.retrieve('tick').hasClass('error') || field.required == false){
			element.retrieve('tick').removeClass('error').addClass('success');
			element.retrieve('error_message').addClass('hidden');
		}
	},
	
	/*
	 * Generic getter for supported elements
	 */
	getValue: function(element){
		var field = element.retrieve('constraints');
		
		switch(element.tagName.toLowerCase()){
			case 'input': 
				if (element.retrieve('constraints').specific_type == 'fk')
					return ($(field.id).get('value') == 0) ? false : $(field.id).get('value');
				else if (element.get('type') == 'text' || element.get('type') == 'password' || element.get('type') == 'file'){
					return element.get('value');
				}	
				break;
			case 'textarea':
				if (typeOf(window.CKEDITOR) == 'object' && this.inArray(field.id, ckFields)){
					return CKEDITOR.instances[element.get('id')].document.getBody().$.innerHTML;
				} else
					return element.get('value');
				break;
			case 'select':
				return (element.getSelected().length > 0) ? true : false;
				break;
		}
		
		return false;
	},
	
	/*
	 * Generic setter for supported elements
	 */
	setValue: function(element, value){
		switch(element.tagName.toLowerCase()){
			case 'input': 
				if (element.get('type') != 'password')
					element.set('value', value);
				break;
			case 'textarea':
				if (typeOf(window.CKEDITOR) == 'object' && this.inArray(element.get('id'), ckFields)){
					CKEDITOR.instances[element.get('id')].document.getBody().$.innerHTML = value;
				} else
					element.set('value', value);
				break;
		}
	},
	
	/*
	 * Checks if a value is in an array
	 */
	inArray: function(needle, haystack){
		for ( i = 0; i < haystack.length; i++){
			if (haystack[i] == needle)
				return true;
		}
		return false;
	},
	
	/*
	 * Filter : IPv4
	 */
	type_isIpV4: function(ip){
		return /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:[.](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/.test(ip);
	},
	
	/*
	 * Filter : IPv6
	 */
	type_isIpV6: function(ip){
		return /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/.test(ip);
	},
	
	/*
	 * Builds and adds (error/success) tick to a field
	 */
	buildTick: function(element){
		var tick = new Element('span', {
			'class' : 'tick',
			'styles' : {
				'top' : (element.getParent('div.row').getCoordinates().height-16)/2
			}
		}).inject(element.getParent('div.row'));
		
		var error_message = new Element('span', {
			'class' : 'error_message hidden',
			'styles' : {
				'top' : (element.getParent('div.row').getCoordinates().height-28)/2
			}
		}).inject(element.getParent('div.row'));
		
		element.store('tick', tick);
		element.store('error_message', error_message);
	},
	
	/*
	 * Adds or removes success tick to the field if this one doesn't have any errors
	 */
	check: function(element){
		var field = element.retrieve('constraints');
		if ((!element.retrieve('tick').hasClass('error') && field.required == true) || (!element.retrieve('tick').hasClass('error') && field.required == false && this.getValue(element)))
			element.retrieve('tick').addClass('success');
		else if (element.retrieve('tick').hasClass('success') && field.required == false && !this.getValue(element))
			element.retrieve('tick').removeClass('success');
	},
	
	/*
	 * Checks if the form contains errors and prevent it to submit if there are any
	 */
	formState: function(){
		this.submit.addEvent('click', function(e){
			if ($$('input:focus').length > 0) $$('input:focus')[0].fireEvent('blur');
		}.bind(this));
		
		var ticks = $$('div.row span.tick').filter(function(element){
			if (element.hasClass('error')) return element;
		});
		
		if (ticks.length > 0){
			this.form.addEvent('submit', function(e){
				e.stop();
			});
			this.submit.setStyles({'opacity' : 0.5});
		} else {
			this.form.removeEvents();
			this.submit.setStyles({'opacity' : 1});
		}
	}
});

window.addEvent('domready', function(){
	if (typeOf(window.CKEDITOR) == 'object'){
		var counter = 0;
		var limit = ckFields.length;
		CKEDITOR.on('instanceReady', function(e){
			counter++;
			if (counter == limit) formCheck = new FormCheck(slsBoBuild.langs);
		});
	} else
		formCheck = new FormCheck(slsBoBuild.langs);
});